#include "SymbolTable.h"
#include "../../utils/BOOL.h"
#include "../../utils/log.h"

string_ptr SymbolTable::UTF8 = make_string_ptr("UTF-8");
BOOL_ptr SymbolTable::JVM_16 = BOOL::TRUE;
SymbolTable_ptr SymbolTable::global = SymbolTable_ptr(new SymbolTable(32768));

SymbolTable::SymbolTable(int tableSize)
{
  this->indexMask = tableSize - 1;
  // UTF8 = "UTF-8";
  // JVM_16 = BOOL::TRUE;
  // global = new SymbolTable(32768);
  entries = std::make_shared<std::list<std::shared_ptr<SymbolTable::Entry>>>();
  for (int i = 0; i < tableSize; i++)
  {
    entries->push_back(std::shared_ptr<SymbolTable::Entry>());
  }
}

std::wstring SymbolTable::addSymbol(std::wstring buffer, int offset, int len, long hash_)
{
  int bucket = ((int)hash_) & indexMask;

  auto it = entries->begin();
  LOG_INFO << "bucket:" << bucket;
  std::advance(it, bucket);
  std::shared_ptr<SymbolTable::Entry> entry = (*it);
  if (entry != NULL)
  {
    if (hash_ == entry->hash)
    {
      return entry->value;
    }

    std::wstring str = JVM_16 ? subString(buffer, offset, len) : buffer.substr(offset, len);

    return str;
  }

  std::wstring str = JVM_16 ? subString(buffer, offset, len) : buffer.substr(offset, len);
  auto tmp = std::shared_ptr<SymbolTable::Entry>(new Entry(hash_, len, str));
  entry = tmp;
  return str;
}

std::wstring SymbolTable::addSymbol(wchar_t *buffer, int offset, int len, long hash_)
{
  int bucket = ((int)hash_) & indexMask;

  auto it = entries->begin();
  std::advance(it, bucket);
  std::shared_ptr<SymbolTable::Entry> entry = (*it);
  if (entry != NULL)
  {
    if (hash_ == entry->hash)
    {
      return entry->value;
    }

    std::wstring str = subString(buffer, offset, len);

    return str;
  }

  std::wstring str = subString(buffer, offset, len);
  auto tmp = std::shared_ptr<SymbolTable::Entry>(new Entry(hash_, len, str));
  entry = tmp;
  return str;
}

std::wstring SymbolTable::addSymbol(std::wstring symbol, long hash_)
{
  int bucket = ((int)hash_) & indexMask;

  auto it = entries->begin();
  std::advance(it, bucket);
  std::shared_ptr<SymbolTable::Entry> entry = (*it);
  if (entry != NULL)
  {
    if (hash_ == entry->hash)
    {
      return entry->value;
    }

    return symbol;
  }

  auto tmp = std::shared_ptr<SymbolTable::Entry>(new Entry(hash_, symbol.length(), symbol));
  entry = tmp;
  return symbol;
}

std::wstring SymbolTable::findSymbol(long hash_)
{
  int bucket = ((int)hash_) & indexMask;
  auto it = entries->begin();
  std::advance(it, bucket);
  std::shared_ptr<SymbolTable::Entry> entry = (*it);
  if (entry != NULL && entry->hash == hash_)
  {
    return entry->value;
  }
  return L"";
}

std::wstring SymbolTable::subString(std::wstring src, int offset, int len)
{
  // char* chars = new char[len];
  // src->getChars(offset, offset + len, chars, 0);
  // return new string_ptr (chars);
  return src.substr(offset, len);
}

std::wstring SymbolTable::subString(wchar_t *bytes, int from, int len)
{
  // char* strBytes = new byte[len];
  // System->arraycopy(bytes, from, strBytes, 0, len);
  // return new string_ptr (strBytes, UTF8);
  std::wstring src = bytes;
  return src.substr(from, len);
}

SymbolTable::Entry::Entry(long hash, int len, std::wstring value)
{
  this->hash = hash;
  this->len = len;
  this->value = value;
}
